#!/usr/bin/env ruby
$stderr.puts "#{Time.now} Loading service script"

require 'syslog/logger'
$logger = Syslog::Logger.new 'scorebot-service'

pid_path = File.expand_path('../../tmp/pids/service.pid', __FILE__)
File.open(pid_path, 'w') do |f|
  f.puts Process.pid.to_s
end
at_exit do
  FileUtils.rm pid_path
end
require ::File.expand_path('../../config/environment',  __FILE__)

ROUND_LENGTH = Round::ROUND_LENGTH

require 'celluloid/autostart'
class Heartbeat
  include Celluloid

  attr_accessor :redis, :timer

  def initialize
    self.redis = $redis
  end

  def schedule
    self.timer = every(1){ heartbeat }
  end

  def heartbeat
    redis.publish channel_name, 'ok'
  end

  def channel_name
    "scorebot_service_heartbeat_#{Rails.env}"
  end
end

def l(str)
  Scorebot.log str
end

def now_sec
  Time.now.to_i
end

def chillax(ending)
  l "Waiting #{ending - now_sec} seconds"
  if (ending - now_sec) > 5
    midpoint = now_sec + ((ending - now_sec) / 2)
  else
    # never reached
    midpoint = ending + 1
  end

  while now_sec < ending
    if (now_sec > midpoint) && (ending - now_sec > 5)
      midpoint = now_sec + ((ending - now_sec) / 2)
      l "Waiting #{ending - now_sec} more seconds"
    end
    sleep 0.1
  end
end

heartbeat = Heartbeat.new
heartbeat.schedule
l "started heartbeat on #{heartbeat.channel_name}"

if Round.current.nil?
  l "No current round. Press enter to start game."
  ServiceState.new('waiting_to_start').publish! rescue nil
  gets

  new_round = Round.create
  l "Commencing..."

  ServiceState.new('commencing').publish! rescue nil
  new_round.commence!
  l "It's on!"
end

loop do
  loop_start = Time.now

  current_round = Round.current

  unless Timer.round.ended?

    round_timer = Timer.round.reload
    ending_sec = round_timer.ending.to_i

    unless current_round.availability_checks_done?
      l "Scheduling service checks"
      ServiceState.new('scheduling').publish! rescue nil

      Service.all.each do |s|
        l "#{s.name} #{s.enabled.pretty_inspect}"
      end

      checks = Service.enabled.map do |service|
        l "Scheduling #{service.name}"
        check = AvailabilityCheck.for_service service
        check.deadline = round_timer.ending

        if check.gonna_run_long?
          l "Looks like #{service.name} checks will run long :("
        end

        time = check.schedule!

        l "Checking #{service.name} in #{time} seconds"

        check
      end
      l "Waiting for service checks"
      checks.each(&:join)
      l "Service checks done"
    end

    l "Waiting for round end"

    ServiceState.new('waiting_to_end').publish! rescue nil
    chillax ending_sec

  end

  current_round.transaction do
    l "Ending round"
    ServiceState.new('ending').publish! rescue nil
    current_round.ended_at ||= Time.now
    current_round.save

    if Timer.today.ended?
      @ending = true
    else
      new_round = Round.create
      l "Started round #{new_round.id}"

      ServiceState.new('commencing').publish! rescue nil
      StatsD.measure('commence'){ new_round.commence! }
    end

    StatsD.measure('finalize'){ current_round.finalize! }
  end

  # pid = Process.fork do
  #   Dir.chdir Rails.root do
  #     exec 'rake scoreboard:upload'
  #   end
  # end
  # Process.detach pid

  break if @ending
  Round.clear_active_connections!
end
